#include "wxspropertygridmanager.h"
#include "wxspropertycontainer.h"

#include <manager.h>
#include <logmanager.h>

IMPLEMENT_CLASS( wxsPropertyGridManager, wxPropertyGridManager )

wxsPropertyGridManager::wxsPropertyGridManager(
  wxWindow* parent,
  wxWindowID id,
  const wxPoint& pos,
  const wxSize& size,
  long style,
  const wxChar * name ):
  wxPropertyGridManager( parent, id, pos, size, style, name ),
  MainContainer( 0 ) {
  Singleton = this;
  PropertiesList = 0;
}

wxsPropertyGridManager::~wxsPropertyGridManager() {
  PGIDs.Clear();
  PGEntries.Clear();
  PGIndexes.Clear();
  PGContainers.Clear();
  PGContainersSet.clear();
  for( size_t i = 0; i < GetPageCount(); i++ ) {
    ClearPage( i );
  }
  PreviousIndex = -1;
  PreviousProperty = 0;
  if( Singleton == this ) {
    Singleton = 0;
  }
  DeleteTemporaryPropertiesList();
}

void wxsPropertyGridManager::OnChange( wxPropertyGridEvent& event ) {
  wxPGId ID = event.GetProperty();
  for( size_t i = PGIDs.Count(); i-- > 0; ) {
    if( PGIDs[i] == ID ) {
      wxsPropertyContainer* Container = PGContainers[i];
      if( !PGEntries[i]->PGRead( Container, this, ID, PGIndexes[i] ) ) {
        wxString ErrorMsg;
        ErrorMsg << _T( "wxSmith: Couldn't read value from wxsPropertyGridManager" )
                 << _T( ", propgrid name=" ) << PGEntries[i]->GetPGName()
                 << _T( ", date name=" )     << PGEntries[i]->GetDataName()
                 << _T( ", type name=" )     << PGEntries[i]->GetTypeName();
        Manager::Get()->GetLogManager()->DebugLogError( ErrorMsg );
      }
      Container->NotifyPropertyChangeFromPropertyGrid();
      if( Container != MainContainer && MainContainer != 0 ) {
        MainContainer->OnSubPropertyChanged( Container );
      }
      Update( 0 );
      return;
    }
  }
  MainContainer->OnExtraPropertyChanged( this, ID );
}

void wxsPropertyGridManager::OnDoubleClick( wxPropertyGridEvent& event ) {
  int pageIndex = GetSelectedPage();
  if( pageIndex != 1 ) {
    return;
  }
  wxPGId ID = event.GetProperty();
  MainContainer->OnExtraPropertyChanged( this, ID );
}

void wxsPropertyGridManager::Update( wxsPropertyContainer* PC ) {
  if( PC && PGContainersSet.find( PC ) == PGContainersSet.end() ) {
    return;
  }
  for( size_t i = PGIDs.Count(); i-- > 0; ) {
    PGEntries[i]->PGWrite( PGContainers[i], this, PGIDs[i], PGIndexes[i] );
  }
}

void wxsPropertyGridManager::UnbindAll() {
  PGIDs.Clear();
  PGEntries.Clear();
  PGIndexes.Clear();
  PGContainers.Clear();
  PGContainersSet.clear();
  for( size_t i = 0; i < GetPageCount(); i++ ) {
    ClearPage( i );
  }
  PreviousIndex = -1;
  PreviousProperty = 0;
  SetNewMainContainer( 0 );
}

void wxsPropertyGridManager::UnbindPropertyContainer( wxsPropertyContainer* PC, bool doFreeze ) {
  if( PGContainersSet.find( PC ) == PGContainersSet.end() ) {
    return;
  }
  if( PC == MainContainer ) {
    UnbindAll();
    return;
  }
  if( doFreeze ) {
    Freeze();
  }
  for( size_t i = PGIDs.Count(); i-- > 0; ) {
    if( PGContainers[i] == PC ) {
      PGIDs[i]->Hide( true );
      DeleteProperty( PGIDs[i] );
      PGIDs.RemoveAt( i );
      PGEntries.RemoveAt( i );
      PGIndexes.RemoveAt( i );
      PGContainers.RemoveAt( i );
    }
  }
  if( doFreeze ) {
    Thaw();
  }
  if( !PGIDs.Count() ) {
    for( size_t i = 0; i < GetPageCount(); i++ ) {
      ClearPage( i );
    }
    SetNewMainContainer( 0 );
  }
}

long wxsPropertyGridManager::Register( wxsPropertyContainer* Container, wxsProperty* Property, wxPGId Id, long Index ) {
  if( !Property ) {
    return -1;
  }
  if( Property != PreviousProperty ) {
    PreviousIndex = -1;
  }
  if( Index < 0 ) {
    Index = ++PreviousIndex;
  }
  PGEntries.Add( Property );
  PGIDs.Add( Id );
  PGIndexes.Add( Index );
  PGContainers.Add( Container );
  PGContainersSet.insert( Container );
  return Index;
}

void wxsPropertyGridManager::NewPropertyContainerStart() {
  UnbindAll();
  DeleteTemporaryPropertiesList();
}

void wxsPropertyGridManager::NewPropertyContainerAddProperty( wxsProperty* Property, wxsPropertyContainer* Container ) {
  TemporaryPropertiesList* NewItem = new TemporaryPropertiesList;
  NewItem->Property = Property;
  NewItem->Container = Container;
  NewItem->Priority = Property->GetPriority();
  int Priority = NewItem->Priority;
  TemporaryPropertiesList *Prev = 0, *Search;
  for( Search = PropertiesList; Search && Search->Property->GetPriority() >= Priority; Prev = Search, Search = Search->Next );
  NewItem->Next = Search;
  ( Prev ? Prev->Next : PropertiesList ) = NewItem;
}

void wxsPropertyGridManager::NewPropertyContainerFinish( wxsPropertyContainer* Container ) {
  SelectPage( 0 );
  while( PropertiesList ) {
    TemporaryPropertiesList* Next = PropertiesList->Next;
    PropertiesList->Property->PGCreate( PropertiesList->Container, this, GetGrid()->GetRoot() );
    delete PropertiesList;
    PropertiesList = Next;
  }
  SetNewMainContainer( Container );
}

void wxsPropertyGridManager::SetNewMainContainer( wxsPropertyContainer* Container ) {
  MainContainer = Container;
  OnContainerChanged( MainContainer );
}

void wxsPropertyGridManager::DeleteTemporaryPropertiesList() {
  while( PropertiesList ) {
    TemporaryPropertiesList* Next = PropertiesList->Next;
    delete PropertiesList;
    PropertiesList = Next;
  }
}

void wxsPropertyGridManager::StoreSelected( SelectionData* Data ) {
  if( !Data ) {
    Data = &LastSelection;
  }
  Data->m_PageIndex = GetSelectedPage();
  wxPGId Selected = GetSelectedProperty();
  if( Selected != NULL ) {
    Data->m_PropertyName = GetPropertyName( Selected );
  } else {
    Data->m_PropertyName.Clear();
  }
}

void wxsPropertyGridManager::RestoreSelected( const SelectionData* Data ) {
  if( !Data ) {
    Data = &LastSelection;
  }
  if( Data->m_PageIndex < 0 ) {
    return;
  }
  if( Data->m_PageIndex >= ( int )GetPageCount() ) {
    return;
  }
  if( Data->m_PropertyName.IsEmpty() ) {
    return;
  }
  SelectPage( Data->m_PageIndex );
  if( GetPropertyByName( Data->m_PropertyName ) ) {
    SelectProperty( Data->m_PropertyName );
  }
}


wxsPropertyGridManager* wxsPropertyGridManager::Singleton = 0;

BEGIN_EVENT_TABLE( wxsPropertyGridManager, wxPropertyGridManager )
  EVT_PG_CHANGED( -1, wxsPropertyGridManager::OnChange )
  EVT_PG_DOUBLE_CLICK( -1, wxsPropertyGridManager::OnDoubleClick )
END_EVENT_TABLE()
